package com.common.exception;

import com.common.util.ProbjectUtils;
import com.system.constant.HTTPStatus;
import com.system.response.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.ExpiredCredentialsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolationException;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.List;

/**
 * @author zfc
 * @date 2023-04-21 08:53:49
 */
@Slf4j
@Component
@RestControllerAdvice
public class GlobalException {

    @Autowired
    private ProbjectUtils probjectUtils;

    @ExceptionHandler(value = UnauthorizedException.class)
    public Result handler(UnauthorizedException e) {
        System.out.println("e = " + e);
        return new Result().setCode(HTTPStatus.UNAUTHORIZED).setMessage("无权限操作");
    }

    @ExceptionHandler(value = ExpiredCredentialsException.class)
    public Result handler(ExpiredCredentialsException e) {
        System.out.println("e = " + e);
        Subject subject = SecurityUtils.getSubject();
        //清除用户缓存
        probjectUtils.clearAllCache((String) subject.getPrincipal());
        return new Result().setCode(HTTPStatus.FORBIDDEN).setMessage("登录已过期，请重新登录");
    }

    @ExceptionHandler(value = UnauthenticatedException.class)
    public Result handler(UnauthenticatedException e) {
        System.out.println("e = " + e);
        return new Result().setCode(HTTPStatus.UNAUTHORIZED).setMessage("未登录");
    }

    @ExceptionHandler(value = UnknownAccountException.class)
    public Result handler(UnknownAccountException e) {
        System.out.println("e = " + e);
        if (e.getMessage()!=null){
            return new Result().setCode(HTTPStatus.UNAUTHORIZED).setMessage(e.getMessage());
        }else{
            return new Result().setCode(HTTPStatus.UNAUTHORIZED).setMessage("账号错误！！！");
        }
    }


    @ExceptionHandler(value = IncorrectCredentialsException.class)
    public Result handler(IncorrectCredentialsException e) {
        System.out.println("e = " + e);
        return new Result().setCode(HTTPStatus.UNAUTHORIZED).setMessage("密码错误！！！");
    }

    @ExceptionHandler(value = NullPointerException.class)
    public Result handler(NullPointerException e) {
        System.out.println("e = " + e);
        e.printStackTrace();
        return new Result().setCode(HTTPStatus.BAD_REQUEST).setMessage("参数不能为空！");
    }

    @ExceptionHandler(value = NumberFormatException.class)
    public Result handler(NumberFormatException e) {
        System.out.println("e = " + e);
        return new Result().setCode(HTTPStatus.BAD_REQUEST).setMessage("存在非法数字请检查！");
    }

    /**
     * sql key 重复
     * @param e
     * @return
     */
    @ExceptionHandler(value = DataAccessException.class)
    public Result handler(SQLIntegrityConstraintViolationException e){
        System.out.println("e = " + e);
        if (e.getMessage()!=null){
            if(e.getMessage().contains("Duplicate entry")){
                String[] split = e.getMessage().split(" ");
                String msg = split[2] + "已存在。";
                return new Result().setCode(HTTPStatus.BAD_REQUEST).setMessage(msg);
            }
            return new Result().setCode(HTTPStatus.BAD_REQUEST).setMessage(e.getMessage());
        }else{
            return new Result().setCode(HTTPStatus.BAD_REQUEST).setMessage(e.getClass().getName());
        }
    }

    //处理 form data方式调用接口校验失败抛出的异常
    @ExceptionHandler(BindException.class)
    public Result handler(BindException e) {
        System.out.println("e = " + e);
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        String message = fieldErrors.get(0).getDefaultMessage();
        return new Result().setCode(HTTPStatus.BAD_REQUEST).setMessage(message);
    }
    //  处理 json 请求体调用接口校验失败抛出的异常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result handler(MethodArgumentNotValidException e) {
        System.out.println("e = " + e);
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        String message = fieldErrors.get(0).getDefaultMessage();
        return new Result().setCode(HTTPStatus.BAD_REQUEST).setMessage(message);
    }
    //  处理单个参数校验失败抛出的异常
    @ExceptionHandler(ConstraintViolationException.class)
    public Result handler(ConstraintViolationException e) {
        System.out.println("e = " + e);
        String message = e.getMessage().substring(e.getMessage().indexOf(":")+1).trim();
        return new Result().setCode(HTTPStatus.BAD_REQUEST).setMessage(message);
    }




    @ExceptionHandler(value = SQLException.class)
    public Result handler(SQLException e){
        System.out.println("e = " + e);
        if (e.getMessage()!=null){
            return new Result().setCode(HTTPStatus.BAD_REQUEST).setMessage(e.getMessage());
        }else{
            return new Result().setCode(HTTPStatus.BAD_REQUEST).setMessage(e.getClass().getName());
        }
    }
}
